package io.wongxd.solution.compose.helper

import android.annotation.SuppressLint
import android.content.Context
import android.location.*
import androidx.compose.runtime.*
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import io.wongxd.solution.locationTracker.LocationTracker
import io.wongxd.solution.locationTracker.ProviderError
import io.wongxd.solution.logger.WLogUtil
import io.wongxd.solution.permission.PermissionCommons
import java.util.*

fun getLocationTracker(
    onError: (ProviderError) -> Unit = { },
    onGet: (Location) -> Unit
): LocationTracker {
    return LocationTracker(
        minTimeBetweenUpdates = 1000L, // one second
        minDistanceBetweenUpdates = 1F, // one meter
        shouldUseGPS = true,
        shouldUseNetwork = true,
        shouldUsePassive = true
    ).also {
        it.addListener(object : LocationTracker.Listener {
            override fun onLocationFound(location: Location) {
                onGet(location)
            }

            override fun onProviderError(providerError: ProviderError) {

            }
        })
    }
}

class LocationHelper(
    private val ctx: Context,
    justNetwork: Boolean,
    private val pauseAfterSuccess: Boolean,
    private val getAltitude: (Double) -> Unit,
    private val onGetInfo: (location: Location, lat: Double, lon: Double, address: Address?) -> Unit
) {
    private val TAG = "LocationHelper"

    private val tracker: LocationTracker = LocationTracker(
        minTimeBetweenUpdates = 1000L, // one second
        minDistanceBetweenUpdates = 1F, // one meter
        shouldUseGPS = justNetwork.not(),
        shouldUseNetwork = true,
        shouldUsePassive = true
    ).also {
        it.addListener(object : LocationTracker.Listener {
            override fun onLocationFound(location: Location) {
                getAddress(location)
                if (pauseAfterSuccess) onDeActive()
            }

            override fun onProviderError(providerError: ProviderError) {

            }
        })
    }

    //获取地址信息:城市、街道等信息
    private fun getAddress(location: Location?) {
        try {
            if (location != null) {
                val gc = Geocoder(ctx, Locale.getDefault())
                val result = gc.getFromLocation(location.latitude, location.longitude, 1)
                WLogUtil.d("$TAG,获取地址信息：$result，高度:${location.altitude}")
                callbackAltitude(location)
                onGetInfo.invoke(
                    location,
                    location.latitude,
                    location.longitude,
                    result?.filterNotNull()?.first()
                )
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    private fun callbackAltitude(location: Location?) {
        location?.altitude?.let {
            if (it > 0 || it < 0) {
                getAltitude.invoke(it)
            }
        }
    }

    @SuppressLint("MissingPermission")
    private fun getLocation() {
        WLogUtil.d("$TAG,获取地址信息：开始  pauseAfterSuccess:$pauseAfterSuccess")
        tracker.startListening(ctx)
    }

    fun onActive() {
        if (PermissionCommons.checkPermissionGranted(
                ctx,
                *PermissionCommons.REQUIRED_LOCATION_PERMISSIONS
            )
        ) {
            onDeActive()
            getLocation()
        }
    }

    fun onDeActive() {
        WLogUtil.d("$TAG,获取地址信息：暂停")
        try {
            tracker.stopListening()
        } catch (e: Exception) {
        }
    }
}


@Composable
fun LocationCompose(
    justNetwork: Boolean = false,
    pauseAfterSuccess: Boolean = false,
    refreshReqMs: Long = 0L,
    onChange: (location: Location, lat: Double, lon: Double, address: Address?) -> Unit
) {
    val ctx = LocalContext.current

    var rememberAltitude by remember {
        mutableDataSaverStateOf(
            DataSaverPreferences(ctx),
            "LocationCompose.rememberAltitude",
            "0.0"
        )
    }

    var hasGet by remember {
        mutableStateOf(false)
    }

    val locationHelper = remember {
        LocationHelper(ctx,
            justNetwork = justNetwork,
            pauseAfterSuccess = pauseAfterSuccess,
            getAltitude = {
                rememberAltitude = it.toString()
            },
            onGetInfo = { location, lat, lon, address ->
                hasGet = true
                onChange.invoke(location.apply {
                    this.altitude = rememberAltitude.toDouble()
                }, lat, lon, address)
            })
    }

    LaunchedEffect(key1 = refreshReqMs, block = {
        if (refreshReqMs > 0) locationHelper.onActive()
    })

    val lifecycle = LocalLifecycleOwner.current.lifecycle
    DisposableEffect(lifecycle, locationHelper) {
        // Make it follow the current lifecycle
        val lifecycleObserver = LifecycleEventObserver { _, event ->
            when (event) {
                Lifecycle.Event.ON_RESUME -> {
                    if ((pauseAfterSuccess && hasGet).not())
                        locationHelper.onActive()
                }
                Lifecycle.Event.ON_PAUSE -> {
                    locationHelper.onDeActive()
                }
                else -> {}
            }
        }

        lifecycle.addObserver(lifecycleObserver)

        onDispose {
            lifecycle.removeObserver(lifecycleObserver)
        }
    }
}